package dfferber.xstream;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;

public class SanitizedProxyMapper extends MapperWrapper {

	Set<String> proxySuffixes = new HashSet<String>();
	Map<Class<?>, Class<?>> classToSuperClass = new HashMap<Class<?>, Class<?>>();
	Set<Class<?>> ignoreClasses = new HashSet<Class<?>>();
	
	public SanitizedProxyMapper(Mapper wrapped) {
		super(wrapped);
	}
	
	protected Class<?> resolveSuperClass(Class<?> type) {
		if (ignoreClasses.contains(type)) return null;
		Class<?> topClass = classToSuperClass.get(type);
		if (topClass != null) return topClass;

		Class<?> superClass = type;
		while (hasSuffix(superClass)) {
			superClass = superClass.getSuperclass();
		}
		if (superClass.equals(type)) {
			ignoreClasses.add(type);
			return null;
		} else {
			classToSuperClass.put(type, superClass);
			return superClass;
		}
	}

	protected boolean hasSuffix(Class<?> type) {
		Iterator<String> iterator = proxySuffixes.iterator();
		String name = type.getName();
		while (iterator.hasNext()) {
			String suffix = iterator.next();
			if (name.indexOf(suffix) > 1) return true;
		}
		return false;
	}

	@Override
	public Class defaultImplementationOf(Class type) {
		Class<?> superClass = resolveSuperClass(type);
		if (superClass == null) {
			return super.defaultImplementationOf(type);
		} else {
			return super.defaultImplementationOf(superClass);
		}
	}

	@Override
	public boolean isImmutableValueType(Class type) {
		Class<?> superClass = resolveSuperClass(type);
		if (superClass == null) {
			return super.isImmutableValueType(type);
		} else {
			return super.isImmutableValueType(superClass);
		}
	}
	
	@Override
	public String serializedClass(Class type) {
		Class<?> superClass = resolveSuperClass(type);
		if (superClass == null) {
			return super.serializedClass(type);
		} else {
			return super.serializedClass(superClass);
		}
	}
	
	@Override
	public boolean shouldSerializeMember(Class definedIn, String fieldName) {
		Class<?> superClass = resolveSuperClass(definedIn);
		if (superClass == null) {
			return super.shouldSerializeMember(definedIn, fieldName);
		} else {
			return false;
		}
	}

	public void addSuffix(String suffix) {
		this.proxySuffixes.add(suffix);
	}

}
